Skip to content

Feature/#155 google login#159

Merged
ImHyungsuk merged 9 commits intodevelopfrom
feature/#155-google-login
Jan 12, 2026
Merged

Feature/#155 google login#159
ImHyungsuk merged 9 commits intodevelopfrom
feature/#155-google-login

Conversation

@ImHyungsuk
Copy link
Copy Markdown
Contributor

@ImHyungsuk ImHyungsuk commented Nov 21, 2025

📌 PR 요약

🌱 작업한 내용

  • 구글 로그인 클리어

🌱 PR 포인트

  • 하다 컨플릭트 났는데 해결 된듯?

📸 스크린샷

스크린샷
파일첨부바람

📮 관련 이슈

Summary by CodeRabbit

  • 새로운 기능

    • Google 로그인이 기존 로그인 옵션에 추가되어 Google로 간편 로그인할 수 있습니다.
  • 개선

    • 프로필 편집 화면의 레이아웃 간격을 조정하여 UI 정렬이 개선되었습니다.
    • 로그인 버튼 레이블(추가된 문자열 리소스) 등 UI 문구가 확장되었습니다.
  • 작업

    • 릴리스/빌드 설정과 난독화 규칙이 업데이트되어 Google 로그인 관련 설정이 포함되었습니다.

✏️ Tip: You can customize this high-level summary in your review settings.

@ImHyungsuk ImHyungsuk requested a review from a team November 21, 2025 07:37
@ImHyungsuk ImHyungsuk self-assigned this Nov 21, 2025
@ImHyungsuk ImHyungsuk added the 형석 🐧🍀 그날 인류는 떠올렸다 . 진격의 형석서서서석 label Nov 21, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Nov 21, 2025

Walkthrough

구글 웹 클라이언트 ID를 빌드 설정에 추가하고, AndroidX CredentialManager 기반의 GoogleLoginHelper와 OAuth UI/뷰모델 확장을 통해 기존 카카오 로그인에 구글 로그인을 통합했습니다. ProGuard 규칙과 라이브러리 의존성도 추가되었습니다.

Changes

응집도 / 파일(들) 변경 요약
빌드 설정 및 ProGuard
app/proguard-rules.pro, build-logic/convention/.../BuildConfig.kt, gradle/libs.versions.toml
ProGuard 규칙 추가( com.google.gson.TypeAdapter 보존, com.google.googlesignin.** 보존) 및 GOOGLE_WEB_CLIENT_ID 빌드필드, Google Identity/Credentials 관련 라이브러리 버전/의존성 추가.
빌드 필드 공급자
core/common/.../BuildConfigFields.kt, core/buildconfig/.../BuildConfigFieldsProviderImpl.kt
BuildConfigFieldsgoogleWebClientId: String 필드 추가 및 공급자 구현에서 해당 값 전달하도록 업데이트. (공개 API 확장)
OAuth 기능 — 구현 및 의존성
feature/oauth/build.gradle.kts, feature/oauth/.../GoogleLoginHelper.kt
Google Identity / Credentials 의존성 추가 및 CredentialManager를 사용한 GoogleLoginHelper 클래스 추가(구글 ID 토큰 획득).
OAuth 계약 및 뷰모델
feature/oauth/.../OauthContract.kt, feature/oauth/.../OauthViewModel.kt
OauthIntentGoogleLoginClick, GoogleLoginSuccess, GoogleLoginFailure 추가 및 StartGoogleLogin 사이드이펙트 처리 로직/핸들러 추가. 뷰모델에서 구글 로그인 분기 추가.
OAuth UI 및 레이아웃
feature/oauth/.../OauthScreen.kt, feature/mypage/.../ProfileEditScreen.kt
OauthScreen 시그니처에 googleLoginClick 콜백 추가 및 UI에서 구글 로그인 버튼 연결. ProfileEditScreen의 Spacer들 weight → 고정 높이로 변경.
리소스
feature/oauth/.../strings.xml
apple_login 문자열 리소스 추가.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant OauthScreen
    participant OauthViewModel
    participant GoogleLoginHelper
    participant CredentialManager
    participant Backend

    User->>OauthScreen: 구글 로그인 클릭
    OauthScreen->>OauthViewModel: GoogleLoginClick 발송
    OauthViewModel->>OauthScreen: StartGoogleLogin 사이드이펙트 (또는 이벤트)
    OauthScreen->>GoogleLoginHelper: requestGoogleLogin(onSuccess,onFailure)
    GoogleLoginHelper->>CredentialManager: GetCredentialRequest (webClientId 포함)
    CredentialManager->>User: 구글 계정 선택 UI 표시
    User->>CredentialManager: 계정 선택
    CredentialManager->>GoogleLoginHelper: GoogleIdTokenCredential 반환
    GoogleLoginHelper->>OauthScreen: onSuccess(idToken)
    OauthScreen->>OauthViewModel: GoogleLoginSuccess(provider="GOOGLE", accessToken=idToken)
    OauthViewModel->>Backend: postSocialLogin(provider, accessToken)
    Backend->>OauthViewModel: JWT 응답
    OauthViewModel->>OauthViewModel: SaveJwtToken 처리
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 분

Possibly related PRs

Suggested labels

시현🥐🐟

Suggested reviewers

  • leeseokchan00

전체 설명

구글 로그인 기능을 추가합니다. 구글 웹 클라이언트 ID를 빌드 설정에 추가하고, AndroidX CredentialManager를 활용한 GoogleLoginHelper 클래스를 구현하여 구글 인증 토큰을 획득합니다. OAuth 화면과 뷰모델을 확장해 기존 카카오 로그인과 함께 구글 로그인 흐름을 통합합니다.

변경사항

응집도 / 파일(들) 변경 요약
빌드 설정 및 ProGuard
app/proguard-rules.pro, build-logic/convention/.../BuildConfig.kt, gradle/libs.versions.toml
GSON TypeAdapter와 Google Sign-In 관련 클래스 유지를 위한 ProGuard 규칙 추가. Google Web Client ID를 빌드 설정에 추가. Google Identity 및 Credentials 라이브러리 버전 및 의존성 정의.
빌드 설정 필드 확장
core/common/.../BuildConfigFields.kt, core/buildconfig/.../BuildConfigFieldsProviderImpl.kt
BuildConfigFields 데이터 클래스에 googleWebClientId 필드 추가 및 공급자 구현 업데이트.
구글 로그인 구현
feature/oauth/build.gradle.kts, feature/oauth/.../GoogleLoginHelper.kt
Google Credentials 의존성 추가. CredentialManager를 활용한 GoogleLoginHelper 클래스 구현으로 Google ID 토큰 획득 기능 제공.
OAuth 계약 및 흐름
feature/oauth/.../OauthContract.kt, feature/oauth/.../OauthViewModel.kt
GoogleLoginClick, GoogleLoginSuccess, GoogleLoginFailure 인텐트와 StartGoogleLogin 사이드이펙트 추가. 뷰모델에서 구글 로그인 이벤트 처리.
OAuth UI
feature/oauth/.../OauthScreen.kt, feature/mypage/.../ProfileEditScreen.kt
OauthScreen에 googleLoginClick 콜백 추가하고 구글 로그인 버튼 연결. ProfileEditScreen의 Spacer 레이아웃 조정 (고정 높이값 적용).
리소스
feature/oauth/.../strings.xml
apple_login 문자열 리소스 추가.

시퀀스 다이어그램

sequenceDiagram
    actor User
    participant OauthScreen
    participant OauthViewModel
    participant GoogleLoginHelper
    participant CredentialManager
    participant Backend
    
    User->>OauthScreen: 구글 로그인 클릭
    OauthScreen->>OauthViewModel: GoogleLoginClick 발송
    OauthViewModel->>OauthViewModel: StartGoogleLogin 사이드이펙트 생성
    OauthScreen->>GoogleLoginHelper: requestGoogleLogin 호출
    GoogleLoginHelper->>CredentialManager: 자격증명 요청
    CredentialManager->>User: 구글 계정 선택 UI
    User->>CredentialManager: 계정 선택
    CredentialManager->>GoogleLoginHelper: GoogleIdTokenCredential 반환
    GoogleLoginHelper->>OauthScreen: onSuccess (ID 토큰)
    OauthScreen->>OauthViewModel: GoogleLoginSuccess 발송
    OauthViewModel->>Backend: postSocialLogin (provider="GOOGLE", accessToken)
    Backend->>OauthViewModel: JWT 토큰 반환
    OauthViewModel->>OauthViewModel: SaveJwtToken 발송
Loading

코드 리뷰 예상 노력

🎯 3 (Moderate) | ⏱️ ~20 분

  • 특별 주의 사항:
    • GoogleLoginHelper.kt: CredentialManager API 사용법 및 예외 처리 로직 검증 필요
    • OauthViewModel.kt: GoogleLoginSuccess와 기존 postSocialLogin 흐름의 통합 일관성 확인
    • BuildConfigFields.kt 및 관련 공급자: 새 필드의 모든 호출 사이트에서 올바르게 사용되는지 확인
    • ProGuard 규칙의 적절성 및 런타임 반영 검증

관련 PR 가능성

  • [Feature/#3] kakao login sdk #4: BuildConfigFields 데이터 구조와 공급자 수정이 겹친다 (새로운 필드 추가 및 BuildConfigFieldsProviderImpl 업데이트).

제안 라벨

시현🥐🐟

제안 검토자

  • leeseokchan00

🐰 구글 토큰 퐁당, 자격증명에 뛰어들고
작은 발로 클릭하면 ID가 도착해요
카카오와 손잡고 OAuth 춤을 추니
로그인 길이 더 반짝반짝하네 ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning ProfileEditScreen.kt의 레이아웃 간격 수정은 Google 로그인 구현과 무관한 변경사항입니다. ProfileEditScreen.kt의 Spacer 수정사항을 별도의 PR로 분리하거나 해당 변경사항을 이 PR에서 제거하시기 바랍니다.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 풀 리퀘스트의 주요 변경 사항인 Google 로그인 기능을 명확하게 요약하고 있습니다.
Linked Issues check ✅ Passed 연결된 이슈 #155는 Google 로그인 구현에 대한 기능 요청이며, PR의 모든 코드 변경사항이 이를 충족하고 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

♻️ Duplicate comments (2)
feature/mypage/src/main/java/com/teamsolply/solply/mypage/profile/ProfileEditScreen.kt (2)

140-140: 동일한 이슈: 고정 높이 Spacer 검증 필요

Line 129와 동일하게, 이 Spacer도 weight 기반에서 고정 높이(32.dp)로 변경되었습니다.


168-168: 동일한 이슈: 고정 높이 Spacer 검증 필요

Line 129, 140과 동일하게, 이 Spacer도 weight 기반에서 고정 높이(24.dp)로 변경되었습니다.

🧹 Nitpick comments (4)
feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthViewModel.kt (1)

56-76: 디버그 로그 메시지를 개선하세요.

Line 73의 로그 태그 "asdasdasd"는 의미 없는 문자열입니다. 디버깅 시 로그를 식별하기 어렵습니다.

다음과 같이 개선하세요:

         }.onFailure {
-            Log.d("asdasdasd", it.toString())
+            Log.e("OauthViewModel", "Social login failed: ${it.message}", it)
         }
feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthScreen.kt (1)

50-50: GoogleLoginHelper의 생명주기 관리를 고려해보세요.

GoogleLoginHelperremember로 생성되지만 명시적인 정리 로직이 없습니다. 현재는 큰 문제가 없어 보이지만, 향후 리소스 관리가 필요할 경우를 대비하여 DisposableEffect를 사용하는 것을 고려해보세요.

예시:

val googleLoginHelper = remember { GoogleLoginHelper(context = context) }
DisposableEffect(Unit) {
    onDispose {
        // Clean up if needed in the future
    }
}
feature/oauth/src/main/java/com/teamsolply/solply/oauth/GoogleLoginHelper.kt (2)

25-25: 주석 처리된 코드를 정리하세요.

여러 곳에 주석 처리된 코드(SERVER_URL, nonce, 로그 등)가 남아있습니다. 필요한 코드는 활성화하고, 불필요한 코드는 제거하여 코드의 가독성을 높이는 것을 권장합니다.

예시:

  • Line 25: SERVER_URL이 필요하다면 활성화하고, 아니면 제거
  • Lines 69-71: 디버그 로그가 필요하다면 BuildConfig.DEBUG로 조건부 활성화
  • Lines 74, 77, 83: 에러 로그는 활성화 권장

Also applies to: 33-33, 69-71, 74-74, 77-77, 83-83


24-24: BuildConfig를 직접 참조하는 대신 주입받는 것을 고려해보세요.

현재 WEB_CLIENT_ID를 companion object에서 BuildConfig를 직접 참조하고 있습니다. 테스트 용이성과 의존성 명시를 위해 생성자를 통해 주입받는 것을 고려해보세요.

예시:

class GoogleLoginHelper(
    private val context: Context,
    private val webClientId: String = com.teamsolply.solply.buildconfig.BuildConfig.GOOGLE_WEB_CLIENT_ID
) {
    // ...
    private val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
        .setServerClientId(webClientId)
        // ...
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db6473b and a3a96c3.

📒 Files selected for processing (12)
  • app/proguard-rules.pro (1 hunks)
  • build-logic/convention/src/main/java/com/teamsolply/solply/convention/BuildConfig.kt (1 hunks)
  • core/buildconfig/src/main/java/com/teamsolply/solply/buildconfig/impl/BuildConfigFieldsProviderImpl.kt (2 hunks)
  • core/common/src/main/java/com/teamsolply/solply/common/buildconfig/BuildConfigFields.kt (1 hunks)
  • feature/mypage/src/main/java/com/teamsolply/solply/mypage/profile/ProfileEditScreen.kt (3 hunks)
  • feature/oauth/build.gradle.kts (2 hunks)
  • feature/oauth/src/main/java/com/teamsolply/solply/oauth/GoogleLoginHelper.kt (1 hunks)
  • feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthContract.kt (2 hunks)
  • feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthScreen.kt (4 hunks)
  • feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthViewModel.kt (1 hunks)
  • feature/oauth/src/main/res/values/strings.xml (1 hunks)
  • gradle/libs.versions.toml (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthViewModel.kt (4)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
  • postSideEffect (48-52)
remote/oauth/src/main/java/com/teamsolply/solply/oauth/service/OauthService.kt (2)
  • postSocialLogin (10-16)
  • postSocialLogin (11-15)
data/oauth/src/main/java/com/teamsolply/solply/oauth/repository/OauthRepositoryImpl.kt (1)
  • postSocialLogin (13-27)
domain/oauth/src/main/java/com/teamsolply/solply/oauth/repository/OauthRepository.kt (2)
  • postSocialLogin (5-8)
  • postSocialLogin (6-6)
🪛 detekt (1.23.8)
feature/oauth/src/main/java/com/teamsolply/solply/oauth/GoogleLoginHelper.kt

[warning] 73-73: The caught exception is swallowed. The original exception could be lost.

(detekt.exceptions.SwallowedException)

🔇 Additional comments (8)
feature/mypage/src/main/java/com/teamsolply/solply/mypage/profile/ProfileEditScreen.kt (1)

129-130: 고정 높이로 변경된 Spacer의 반응형 동작을 확인하세요.

이 Spacer가 weight 기반에서 고정 높이(16.dp)로 변경되었습니다. 고정 높이는 다양한 화면 크기에서 유연하게 대응하지 못할 수 있습니다. 특히 작은 화면에서는 레이아웃이 잘리거나 의도하지 않은 스크롤이 발생할 수 있습니다.

다양한 화면 크기(특히 작은 기기)에서 UI가 올바르게 표시되는지 확인해주세요.

feature/oauth/build.gradle.kts (1)

1-17: LGTM! Google Sign-In 의존성이 올바르게 추가되었습니다.

Google Sign-In 통합에 필요한 Credential Manager API 라이브러리들(google.id, credentials, credentials.play.auth)과 BuildConfig 접근을 위한 의존성이 적절하게 추가되었습니다.

feature/oauth/src/main/res/values/strings.xml (1)

5-5: PR 목표와의 불일치 확인이 필요합니다.

이 PR의 목표는 구글 로그인 구현인데, apple_login 문자열 리소스가 추가되었습니다. Apple 로그인이 이번 PR의 범위에 포함되는 것이 맞는지 확인이 필요합니다.

feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthContract.kt (2)

15-17: LGTM! Google 로그인 Intent가 일관성 있게 추가되었습니다.

기존 Kakao 로그인 패턴을 따라 Google 로그인 Intent들이 적절하게 추가되었습니다. Click -> Success/Failure 흐름이 명확합니다.


27-27: LGTM! Google 로그인 SideEffect가 추가되었습니다.

Kakao 로그인과 동일한 패턴으로 StartGoogleLogin SideEffect가 추가되어 일관성이 유지됩니다.

core/common/src/main/java/com/teamsolply/solply/common/buildconfig/BuildConfigFields.kt (1)

6-6: LGTM! BuildConfig 필드가 올바르게 추가되었습니다.

googleWebClientId 필드가 data class에 적절하게 추가되었습니다.

build-logic/convention/src/main/java/com/teamsolply/solply/convention/BuildConfig.kt (1)

37-41: 필드 이름의 오타를 수정하세요.

BuildConfig 필드 이름에 오타가 있습니다: GOOGLe_WEB_CLIENT_IDe가 소문자입니다. GOOGLE_WEB_CLIENT_ID로 수정해야 합니다.

다음 diff를 적용하세요:

         buildConfigField(
             "String",
-            "GOOGLE_WEB_CLIENT_ID",
+            "GOOGLE_WEB_CLIENT_ID",
             gradleLocalProperties(rootDir, providers).getProperty("google.web.client.id")
         )

Likely an incorrect or invalid review comment.

core/buildconfig/src/main/java/com/teamsolply/solply/buildconfig/impl/BuildConfigFieldsProviderImpl.kt (1)

4-4: LGTM! Google Web Client ID가 올바르게 구성되었습니다.

BuildConfig에서 GOOGLE_WEB_CLIENT_ID를 가져와 BuildConfigFields에 정상적으로 전달하고 있습니다.

Also applies to: 18-18

Comment thread app/proguard-rules.pro
Comment on lines +23 to +24
-keep class * extends com.google.gson.TypeAdapter
-keep class com.google.googlesignin.** { *; } No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

ProGuard 규칙이 지나치게 광범위할 수 있습니다.

현재 규칙이 매우 넓은 범위를 유지하고 있습니다:

  • * extends TypeAdapter: 모든 TypeAdapter 서브클래스 유지
  • com.google.googlesignin.** { *; }: 모든 Google Sign-In 클래스와 멤버 유지

이는 난독화를 방해하고 APK 크기를 증가시킬 수 있습니다. Google Sign-In Credential Manager API를 사용하는 경우, 더 구체적인 규칙으로 충분할 수 있습니다.

다음 스크립트로 실제 사용되는 Google Sign-In 클래스를 확인하세요:


🏁 Script executed:

#!/bin/bash
# Google Sign-In 관련 import 및 사용 확인
rg -nP --type=kotlin -C3 'import.*google\.android\.gms\.auth|import.*googleid' feature/oauth/

Length of output: 1223


🏁 Script executed:

#!/bin/bash
# Search for actual usage of com.google.googlesignin package
rg -nP --type=kotlin --type=java 'com\.google\.googlesignin' .

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for Gson TypeAdapter usage
rg -nP --type=kotlin --type=java 'TypeAdapter' .

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if Credential Manager classes appear in ProGuard rules already
cat app/proguard-rules.pro

Length of output: 847



🏁 Script executed:

#!/bin/bash
# Check build.gradle for dependencies
fd -e gradle | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search build files for google-signin or gson dependencies
rg -nP 'google.*signin|gson' build.gradle

Length of output: 52


🏁 Script executed:

#!/bin/bash
# Search for any Credential Manager ProGuard rules or missing rules
rg -nP 'credentials|credential' app/proguard-rules.pro

Length of output: 0


사용되지 않는 ProGuard 규칙을 제거하세요.

검증 결과, 코드베이스 어디에서도 다음이 사용되지 않습니다:

  • com.google.googlesignin 패키지 (검색 결과: 0건)
  • TypeAdapter 클래스 (검색 결과: 0건)

현재 구현은 com.google.android.libraries.identity.googleid (Credential Manager API)를 사용하고 있습니다. 라인 23-24의 규칙은 더 이상 필요하지 않은 레거시 Google Sign-In SDK 관련 규칙입니다.

이 규칙들을 제거하면 APK 크기를 줄이고 적절한 난독화가 가능합니다:

-keep class * extends com.google.gson.TypeAdapter
-keep class com.google.googlesignin.** { *; }
🤖 Prompt for AI Agents
In app/proguard-rules.pro around lines 23 to 24, remove the two unused legacy
ProGuard rules for Google Sign-In and Gson TypeAdapter (the lines keeping
com.google.googlesignin.** and classes extending com.google.gson.TypeAdapter);
delete those two lines, run a clean build to confirm no missing symbol or
runtime obfuscation issues, and if build/tests pass, commit the updated proguard
file.

Comment on lines +29 to +34
private val nonce = UUID.randomUUID().toString()
private val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setServerClientId(WEB_CLIENT_ID) // 웹 클라이언트 ID
.setFilterByAuthorizedAccounts(false)
// .setNonce(nonce)
.build()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Nonce 사용이 권장됩니다.

Line 33에서 setNonce(nonce)가 주석 처리되어 있습니다. Nonce는 재생 공격(replay attack)을 방지하는 중요한 보안 메커니즘입니다. 특별한 이유가 없다면 활성화하는 것이 좋습니다.

Nonce를 활성화하세요:

     private val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
         .setServerClientId(WEB_CLIENT_ID) // 웹 클라이언트 ID
         .setFilterByAuthorizedAccounts(false)
-//        .setNonce(nonce)
+        .setNonce(nonce)
         .build()

서버 측에서도 이 nonce를 검증하도록 구현해야 합니다.


이 리뷰 코멘트를 검증하기 위해 저장소를 분석하고 있습니다. 스크립트를 실행 중입니다.


🏁 Script executed:

#!/bin/bash
# Search for the GoogleLoginHelper file and examine its content
find . -name "GoogleLoginHelper.kt" -type f 2>/dev/null | head -5

Length of output: 78


🏁 Script executed:

#!/bin/bash
# Search for GetGoogleIdOption imports and usage patterns
rg -n "GetGoogleIdOption" --type kotlin -B3 -A3

Length of output: 1907


🏁 Script executed:

#!/bin/bash
# Search for nonce-related code and comments in the OAuth module
rg -n "nonce" --type kotlin -i -B2 -A2

Length of output: 1167


🏁 Script executed:

#!/bin/bash
# Search for server-side validation of nonce
rg -n "nonce" --type java --type kotlin -B2 -A2

Length of output: 1167


🏁 Script executed:

#!/bin/bash
# Check for build.gradle or pom.xml to identify Google Sign-In library version
find . -name "build.gradle*" -o -name "pom.xml" | xargs grep -l "google\|gms" 2>/dev/null | head -5

Length of output: 96


🏁 Script executed:

#!/bin/bash
# Search for any comments or documentation explaining why nonce was commented out
rg -n "replay\|setNonce" --type kotlin --type java -B5 -A5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for server-side token validation logic
rg -n "verify|validate" --type kotlin --type java -i | grep -i "token\|nonce\|jwt\|google" | head -10

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check Google Play Services dependency version
find . -name "build.gradle*" | xargs cat 2>/dev/null | grep -A2 -B2 "play.*services.*auth"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for any authentication verification controller or service
fd -e "\.kt$" -e "\.java$" | xargs grep -l "GoogleIdToken\|idToken\|verify" | head -10

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look at the full GoogleLoginHelper.kt file
find . -name "GoogleLoginHelper.kt" -type f 2>/dev/null -exec cat {} \;

Length of output: 3518


🏁 Script executed:

#!/bin/bash
# Search for server endpoint that might validate Google tokens
rg -n "google.*token\|id.*token" --type kotlin --type java -i | head -15

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if there's documentation or configuration about security settings
find . -name "*.md" -o -name "*.txt" | xargs grep -l "nonce\|security" 2>/dev/null | head -5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for any existing issue tracker references or TODOs related to nonce
rg -n "TODO|FIXME|XXX" --type kotlin | grep -i "nonce\|security\|replay"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for Google Sign-In implementation details
rg -n "credentialResponse\|credential" --type kotlin -B3 -A3 | head -30

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check for any security-related tests or validation logic
fd -e "Test.kt" -e "Test.java" | xargs grep -l "nonce\|GoogleLogin" 2>/dev/null

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for the server-side implementation that receives the token
rg -n "id_token\|idToken" --type kotlin --type java | head -15

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for GoogleIdTokenVerifier or similar verification
rg -n "Verifier\|Verify" --type java --type kotlin | grep -i google

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check application properties or configuration for security settings
find . -name "application*.yml" -o -name "application*.properties" | xargs cat 2>/dev/null | grep -i nonce

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look at git history to see if nonce was commented intentionally
git log --oneline feature/oauth/src/main/java/com/teamsolply/solply/oauth/GoogleLoginHelper.kt 2>/dev/null | head -10

Length of output: 104


🏁 Script executed:

#!/bin/bash
# Check for any existing nonce validation on the backend
rg -n "setNonce\|getNonce\|validateNonce" --type java --type kotlin

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for any comments or documentation files
find . -path "*oauth*" -name "*.md" -o -path "*oauth*" -name "README*" 2>/dev/null

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Get broader context about the OAuth implementation
find . -path "*oauth*" -type f \( -name "*.kt" -o -name "*.java" \) | head -20

Length of output: 1603


🏁 Script executed:

#!/bin/bash
# Check for ID token validation on server
rg -n "verify.*IdToken\|validateIdToken" --type java --type kotlin

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for Google API client library usage
rg -n "GoogleIdTokenVerifier\|TokenVerifier" --type java

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if there's any exception handling related to nonce
rg -n "NonceException\|InvalidNonce" --type java --type kotlin

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for the complete token exchange process
rg -n "exchange\|credential.*token" --type kotlin -B2 -A2 | head -30

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for server endpoint path that handles token verification
rg -n "@PostMapping\|@GetMapping\|@PutMapping" --type kotlin | grep -i "token\|auth\|google\|login"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if nonce is being used elsewhere in the codebase
find . -type f \( -name "*.kt" -o -name "*.java" \) -exec grep -l "nonce" {} \;

Length of output: 78


🏁 Script executed:

#!/bin/bash
# Look for documentation on Google Sign-In requirements
find . -name "*.md" -o -name "*.txt" -o -name "*.adoc" 2>/dev/null | xargs grep -l "Google\|OAuth\|Sign-In" 2>/dev/null | head -5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check for any vulnerability scanning or security audit files
find . -name "*.json" -o -name "*.yaml" | xargs grep -l "security\|vulnerability\|nonce" 2>/dev/null | head -5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Get imports from GoogleLoginHelper to understand the library version
rg -n "^import" feature/oauth/src/main/java/com/teamsolply/solply/oauth/GoogleLoginHelper.kt 2>/dev/null || rg -n "^import" . --type kotlin | grep -i google | head -10

Length of output: 709


🏁 Script executed:

#!/bin/bash
# Check the Google Sign-In Android library documentation reference
cat build.gradle.kts 2>/dev/null || cat build.gradle 2>/dev/null || find . -name "build.gradle*" -type f | head -1 | xargs cat

Length of output: 637


🏁 Script executed:

#!/bin/bash
# Look for any recent commit messages about nonce
git log --all --grep="nonce" --oneline 2>/dev/null || echo "No git history available"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Final check: get the exact structure of the GoogleLoginHelper.kt file around the nonce area
find . -name "GoogleLoginHelper.kt" -type f 2>/dev/null -exec head -50 {} \;

Length of output: 1954


🏁 Script executed:

#!/bin/bash
# Look for server-side Google token verification configuration
find . -name "*.properties" -o -name "*.yml" -o -name "*.yaml" 2>/dev/null | xargs grep -i "google\|client.*id\|secret" 2>/dev/null | head -15

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check for Spring Security or other security framework configuration
rg -n "@EnableWebSecurity\|@Configuration\|securityFilterChain" --type java -B2 -A10 | head -40

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for JWT or token parsing logic
rg -n "JwtDecoder\|verifyIdToken\|parseToken" --type java -B2 -A5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for Google client library initialization
rg -n "GoogleCredential\|GoogleAuthorizationCodeFlow\|GoogleClientSecrets" --type java

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if nonce validation happens in a filter or interceptor
rg -n "OncePerRequestFilter\|HandlerInterceptor" --type java -B2 -A10

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Get comprehensive view of OAuth module structure
find feature/oauth -type f 2>/dev/null | head -30

Length of output: 525


🏁 Script executed:

#!/bin/bash
# Look at documentation or SECURITY.md files
find . -iname "*security*" -type f 2>/dev/null | head -10

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check for any architecture decision records or ADRs
find . -iname "*adr*" -o -iname "*decision*" -type f 2>/dev/null | head -10

Length of output: 94


🏁 Script executed:

#!/bin/bash
# Final comprehensive search for nonce implementation
rg -rn "nonce" --type-list 2>/dev/null | head -5
rg -rn "nonce" . 2>/dev/null | head -20

Length of output: 229


🏁 Script executed:

#!/bin/bash
# Check if setNonce is available in the GetGoogleIdOption API
rg -n "GetGoogleIdOption" . --type kotlin -A20 2>/dev/null | head -40

Length of output: 4825


🏁 Script executed:

#!/bin/bash
# Look for version constraints or documentation
cat README.md 2>/dev/null | grep -i "google\|oauth\|security" || echo "No README or no matches"

Length of output: 71


🏁 Script executed:

#!/bin/bash
# Check all files in the OAuth feature module
ls -la feature/oauth/ 2>/dev/null || find . -path "*oauth*" -type d | head -5

Length of output: 289


🏁 Script executed:

#!/bin/bash
# Last attempt - find the exact file and show context
find . -name "GoogleLoginHelper.kt" 2>/dev/null -exec echo "=== File: {} ===" \; -exec cat {} \;

Length of output: 3611


🏁 Script executed:

#!/bin/bash
# Check for Google Play Services version in dependencies
rg -n "com\.google\.android\.gms" . --type kotlin --type java | head -10

Length of output: 306


🏁 Script executed:

#!/bin/bash
# Look for version strings
rg -n "gms:play-services.*auth" . | head -5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if there's a docs folder
find . -type d -name "docs" -o -type d -name "documentation" 2>/dev/null

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for any CHANGELOG or release notes
find . -iname "CHANGELOG*" -o -iname "RELEASE*" 2>/dev/null | xargs grep -i nonce 2>/dev/null

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Verify the exact lines mentioned in the review
sed -n '29,34p' feature/oauth/src/main/java/com/teamsolply/solply/oauth/GoogleLoginHelper.kt 2>/dev/null || echo "File path may differ"

Length of output: 278


🌐 Web query:

Google Identity Services GetGoogleIdOption setNonce method API documentation

💡 Result:

setNonce is a method on GetGoogleIdOption.Builder that sets the nonce used when generating a Google ID token. Use it when you build GetGoogleIdOption to have the ID token include the provided nonce.

Example (Kotlin):
val googleIdOption = GetGoogleIdOption.Builder()
.setServerClientId(WEB_CLIENT_ID)
.setNonce(nonce)
.build()

Docs: GetGoogleIdOption.Builder (method: setNonce). [1][2]

Sources
[1] GetGoogleIdOption.Builder — Google Developers reference.
[2] Authenticate users with Sign in with Google (Android) — example showing setNonce.


🌐 Web query:

androidx.credentials GetGoogleIdOption.Builder setNonce API

💡 Result:

Yes — GetGoogleIdOption.Builder has a setNonce(...) method. It accepts a String nonce and sets the nonce used when generating the Google ID token.

Signatures / usage examples:

  • Kotlin: .setNonce(nonce: String?) on GetGoogleIdOption.Builder. [1]
  • Java: public @nonnull GetGoogleIdOption.Builder setNonce(String nonce). [2]

Example (Kotlin):
val googleIdOption = GetGoogleIdOption.Builder()
.setServerClientId(WEB_CLIENT_ID)
.setNonce(nonce)
.build()

Sources:
[1] Android Developers — Credential Manager: GetGoogleIdOption.Builder (example).
[2] Google Developers reference — GetGoogleIdOption.Builder API.


🌐 Web query:

Google Sign-In nonce replay attack prevention Android 2024 2025

💡 Result:

Short answer — use Google’s nonce support + server-side single-use verification and device attestation:

Key points and recommended implementation

  • Include a cryptographically strong nonce in each Android Sign‑in with Google request (setNonce / setNonce(nonce)). This nonce is intended to prevent replay attacks. [1][2][3]
  • Generate the nonce server‑side or in the app using a CSPRNG (unpredictable), encode URL‑safe Base64, and meet provider rules (recommend ≥16 bytes). Treat each nonce as single‑use. Store/hash it server‑side and mark consumed when an ID token/response is accepted. Reject reused or expired nonces. [2][4]
  • Verify the ID token on your backend: verify signature, aud/client_id, exp/iat, and that the token contains the same nonce you issued. Only accept tokens whose nonce matches a currently valid, unused nonce. [1][3]
  • Optionally harden high‑value flows by combining nonce with a request hash or a server‑issued unique value and using Play Integrity / SafetyNet attestation (nonce field) to bind the response to the specific request and detect tampering. Check and verify attestation tokens server‑side. [4][5]
  • For OAuth code flows, also use PKCE on top of the above; for OIDC ID tokens rely on the nonce claim to prevent replay. [3]

Quick checklist

  1. Generate CSPRNG nonce (server or app), URL‑safe Base64, ≥16 bytes. [4]
  2. Call setNonce(...) when building the Google sign‑in request on Android. [1][2][6]
  3. Exchange/receive ID token on server; verify signature, aud, exp, iat, and nonce == stored value. Mark nonce used. [1][3]
  4. Consider Play Integrity / SafetyNet attestation and request-specific hashes for extra protection. [4][5]

Sources
[1] Google Identity Android docs — BeginSignInRequest / GetSignInIntentRequest nonce docs.
[2] Android Developer: Authenticate users with Sign in with Google (nonce guidance).
[3] Google Sign‑in / OpenID Connect guidance (ID token verification / nonce role).
[4] Play Integrity and SafetyNet docs — using nonce to prevent replay/tampering.
[5] Google Sign‑in Security bundle / claims (auth_time and additional trust signals).


Nonce 활성화 및 서버 측 검증 구현 필요

클라이언트: GetGoogleIdOption.BuildersetNonce() 메서드가 Google 공식 API에서 지원되며, nonce는 재생 공격 방지를 위한 표준 보안 메커니즘입니다. 현재 nonce가 생성되었으나(29줄) 주석 처리되어 사용되지 않고 있습니다.

서버: 저장소 검색 결과 nonce 검증 로직이 존재하지 않습니다. Google 문서에 따르면 서버는 ID 토큰의 nonce 클레임을 발급된 nonce와 비교하여 검증해야 하며, 각 nonce는 단일 사용 용도로 취급되어야 합니다.

    private val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
        .setServerClientId(WEB_CLIENT_ID) // 웹 클라이언트 ID
        .setFilterByAuthorizedAccounts(false)
-//        .setNonce(nonce)
+        .setNonce(nonce)
        .build()

서버 측에서 이 nonce를 ID 토큰의 nonce 클레임과 대조하여 검증하는 로직을 구현해야 합니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private val nonce = UUID.randomUUID().toString()
private val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setServerClientId(WEB_CLIENT_ID) // 웹 클라이언트 ID
.setFilterByAuthorizedAccounts(false)
// .setNonce(nonce)
.build()
private val nonce = UUID.randomUUID().toString()
private val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setServerClientId(WEB_CLIENT_ID) // 웹 클라이언트 ID
.setFilterByAuthorizedAccounts(false)
.setNonce(nonce)
.build()
🤖 Prompt for AI Agents
In feature/oauth/src/main/java/com/teamsolply/solply/oauth/GoogleLoginHelper.kt
around lines 29–34, the client creates a nonce but it's commented out and also
generated as a single class-level val; enable nonce usage and make it
per-login-request by generating a fresh UUID for each auth attempt and pass it
to GetGoogleIdOption.setNonce(nonce). On the server side, implement persistent
single-use nonce handling: when starting an auth flow persist the nonce (e.g.,
DB/Redis) with an expiry, accept the ID token from the client and decode its
nonce claim, compare it to the stored nonce, reject mismatches or
expired/nonexistent nonces, and delete/mark the nonce as used so it cannot be
reused.

private val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build()
private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.Main)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

생명주기를 고려하지 않은 CoroutineScope가 메모리 누수를 유발할 수 있습니다.

CoroutineScope(Dispatchers.Main)을 직접 생성하면 Activity/Fragment가 종료되어도 코루틴이 계속 실행될 수 있습니다.

다음 중 하나를 적용하세요:

  1. 권장: Activity의 lifecycleScope를 파라미터로 받기
class GoogleLoginHelper(
    private val context: Context,
    private val scope: CoroutineScope
)
// Usage: GoogleLoginHelper(context, lifecycleScope)
  1. 대안: SupervisorJob을 사용하고 명시적으로 취소
private val job = SupervisorJob()
private val coroutineScope = CoroutineScope(Dispatchers.Main + job)

fun dispose() {
    job.cancel()
}
🤖 Prompt for AI Agents
In feature/oauth/src/main/java/com/teamsolply/solply/oauth/GoogleLoginHelper.kt
around line 38, the helper creates a raw CoroutineScope with Dispatchers.Main
which can outlive Activity/Fragment and cause memory leaks; change the class to
accept a CoroutineScope (preferably lifecycleScope) as a constructor parameter
and use that scope for launches, or alternatively create the scope with a
SupervisorJob combined with Dispatchers.Main and expose a dispose/clear method
that cancels the job; update usages to pass lifecycleScope from
Activities/Fragments when instantiating the helper.

Comment on lines +51 to +54
} catch (e: GetCredentialException) {
Log.e("Google Sign-in failed", " ${e.localizedMessage}")
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

에러 발생 시 onFailure 콜백이 호출되지 않습니다.

GetCredentialException이 발생하면 로그만 남기고 onFailure 콜백을 호출하지 않아 UI가 로그인 실패를 감지하지 못합니다. 사용자는 로그인이 진행 중인지 실패했는지 알 수 없게 됩니다.

다음과 같이 수정하세요:

             } catch (e: GetCredentialException) {
                 Log.e("Google Sign-in failed", " ${e.localizedMessage}")
+                onFailure(e.localizedMessage ?: "구글 로그인에 실패하였습니다.")
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (e: GetCredentialException) {
Log.e("Google Sign-in failed", " ${e.localizedMessage}")
}
}
} catch (e: GetCredentialException) {
Log.e("Google Sign-in failed", " ${e.localizedMessage}")
onFailure(e.localizedMessage ?: "구글 로그인에 실패하였습니다.")
}
}
🤖 Prompt for AI Agents
In feature/oauth/src/main/java/com/teamsolply/solply/oauth/GoogleLoginHelper.kt
around lines 51–54, the catch block for GetCredentialException currently only
logs the error so the UI never learns the login failed; update the catch to
invoke the provided onFailure callback with the exception (e.g., onFailure(e))
so failure is propagated to the caller, and if onFailure must run on the UI
thread, post/invoke it on the main thread before returning.

Comment on lines +73 to +75
} catch (e: GoogleIdTokenParsingException) {
// Log.e(TAG, "Received an invalid google id token response", e)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

예외가 삼켜지고 있습니다.

GoogleIdTokenParsingException이 발생해도 아무 처리도 하지 않아 사용자가 실패를 알 수 없습니다. Detekt도 이를 경고하고 있습니다.

예외 발생 시 실패 콜백을 호출하세요:

                     } catch (e: GoogleIdTokenParsingException) {
-//                        Log.e(TAG, "Received an invalid google id token response", e)
+                        Log.e(TAG, "Received an invalid google id token response", e)
+                        onFailure("구글 로그인 토큰 파싱에 실패하였습니다.")
                     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (e: GoogleIdTokenParsingException) {
// Log.e(TAG, "Received an invalid google id token response", e)
}
} catch (e: GoogleIdTokenParsingException) {
Log.e(TAG, "Received an invalid google id token response", e)
onFailure("구글 로그인 토큰 파싱에 실패하였습니다.")
}
🧰 Tools
🪛 detekt (1.23.8)

[warning] 73-73: The caught exception is swallowed. The original exception could be lost.

(detekt.exceptions.SwallowedException)

🤖 Prompt for AI Agents
In feature/oauth/src/main/java/com/teamsolply/solply/oauth/GoogleLoginHelper.kt
around lines 73-75, the catch block for GoogleIdTokenParsingException currently
swallows the exception; replace it so the exception is logged and the login
failure path is invoked (e.g., call the existing failure callback or listener
with the exception or an appropriate error object). Ensure you do not rethrow
unnecessarily, but propagate the error to the caller by invoking the module's
failure callback (and include the exception in the log message and callback
parameters).

Comment on lines +68 to +79
OauthSideEffect.StartGoogleLogin -> googleLoginHelper.requestGoogleLogin(
onSuccess = { accessToken ->
viewModel.sendIntent(
OauthIntent.GoogleLoginSuccess(
provider = "GOOGLE",
accessToken = accessToken
)
)
},
onFailure = {}
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

구글 로그인 로직이 중복되어 있습니다.

구글 로그인 로직이 두 곳에 중복 구현되어 있습니다:

  1. Lines 68-79: OauthSideEffect.StartGoogleLogin 사이드 이펙트 처리
  2. Lines 88-100: googleLoginClick 콜백에서 직접 호출

이는 의도하지 않은 동작을 유발할 수 있습니다. 카카오 로그인과 동일하게 ViewModel을 통한 단일 플로우만 사용하는 것을 권장합니다.

다음과 같이 수정하여 카카오 로그인과 일관된 패턴을 유지하세요:

     OauthScreen(
         kakaoLoginClick = { viewModel.sendIntent(OauthIntent.KakaoLoginClick) },
-        googleLoginClick = {
-            googleLoginHelper.requestGoogleLogin(
-                onSuccess = { accessToken ->
-                    viewModel.sendIntent(
-                        OauthIntent.GoogleLoginSuccess(
-                            provider = "GOOGLE",
-                            accessToken = accessToken
-                        )
-                    )
-                },
-                onFailure = {}
-            )
-        }
+        googleLoginClick = { viewModel.sendIntent(OauthIntent.GoogleLoginClick) }
     )

Also applies to: 88-100

🤖 Prompt for AI Agents
In feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthScreen.kt around
lines 68-79 and 88-100 there is duplicated Google login logic: the same
googleLoginHelper.requestGoogleLogin call is invoked both from the
OauthSideEffect.StartGoogleLogin handler and from the googleLoginClick callback.
Remove the direct request call from the googleLoginClick callback (lines
~88-100) and instead dispatch a single ViewModel intent from the click handler
(e.g., send an intent like OauthIntent.StartGoogleLogin or similar) so that the
side-effect handler (lines ~68-79) is the sole place that calls
googleLoginHelper.requestGoogleLogin; also propagate success/failure through the
existing ViewModel intents rather than handling login directly in the UI
callback.

)
)
},
onFailure = {}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

에러 처리가 누락되었습니다.

onFailure 콜백이 빈 람다 {}로 처리되어 있어 사용자가 로그인 실패를 알 수 없습니다. 최소한 로그를 남기거나 사용자에게 토스트/스낵바로 알려주는 것을 권장합니다.

예시:

onFailure = { errorMessage ->
    Log.e("OauthScreen", "Google login failed: $errorMessage")
    // TODO: Show error message to user
}

Also applies to: 98-98

🤖 Prompt for AI Agents
In feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthScreen.kt around
lines 77 and 98, the onFailure callbacks are empty lambdas so login failures are
swallowed; update both callbacks to accept the error (or message) parameter, log
the error (e.g., Log.e with a clear tag and message) and surface feedback to the
user (show a Toast or Snackbar with a user-friendly message); ensure you handle
nullable/unknown error text safely and avoid crashing when showing the UI
feedback.

Comment on lines +28 to +37
OauthIntent.GoogleLoginClick -> postSideEffect(OauthSideEffect.StartGoogleLogin)

is OauthIntent.GoogleLoginSuccess -> postSocialLogin(
provider = intent.provider,
oauthAccessToken = intent.accessToken
)

is OauthIntent.GoogleLoginFailure -> {
TODO()
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Google 로그인 실패 처리를 구현해야 합니다.

Google 로그인 흐름이 추가되었으나 GoogleLoginFailure의 에러 처리가 TODO()로 남아있습니다. 이는 런타임 시 NotImplementedError를 발생시킵니다.

사용자에게 적절한 에러 메시지를 표시하거나 로그를 남기는 등의 에러 처리가 필요합니다.

Kakao 로그인 실패 처리도 동일하게 TODO()로 남아있습니다(Line 24-26). 두 경우 모두 에러 처리 구현이 필요합니다. 에러 처리 구현을 도와드릴까요?

🤖 Prompt for AI Agents
feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthViewModel.kt around
lines 24-26 and 28-37: both KakaoLoginFailure and GoogleLoginFailure currently
call TODO() which throws NotImplementedError at runtime; replace each TODO with
concrete failure handling by posting an appropriate side effect (e.g.,
postSideEffect(OauthSideEffect.ShowError(...)) with a user-friendly message and
include/log the underlying error for diagnostics), and ensure any cleanup or
state reset needed after a failed social login is performed (e.g., clear loading
state or reset flags).

Comment thread gradle/libs.versions.toml
Comment on lines +93 to +94
credentials = "1.6.0-beta03"
googleid = "1.1.1"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

라이브러리 버전 확인이 필요합니다.

credentials 라이브러리가 베타 버전(1.6.0-beta03)을 사용하고 있습니다. 프로덕션 환경에서는 안정 버전 사용을 권장합니다.

다음 명령으로 최신 안정 버전을 확인하세요:


🌐 Web query:

What is the latest stable version of androidx.credentials library?

💡 Result:

The latest stable release is androidx.credentials:credentials version 1.5.0 (released March 12, 2025). [1]

Sources
[1] Android Jetpack — Credentials release notes.


최신 정보를 확인하기 위해 추가 검색이 필요합니다.

프로덕션 환경에서는 안정 버전(1.5.0)을 사용하는 것을 권장합니다.

코드가 아직 베타 단계인 androidx.credentials:credentials:1.6.0-beta03을 사용 중입니다. 최신 안정 버전은 1.5.0입니다. 베타 버전은 미완성 기능과 잠재적 버그가 포함될 수 있으므로, 프로덕션 배포 전에 안정 버전으로 변경하세요.

credentials = "1.5.0"으로 변경하거나, 1.6.0 베타 버전 사용이 필수인 경우 그 이유를 명시하세요.

🤖 Prompt for AI Agents
gradle/libs.versions.toml lines 93-94: the project references the beta artifact
androidx.credentials:credentials 1.6.0-beta03 which is not recommended for
production; update the version to the latest stable release by changing
credentials = "1.6.0-beta03" to credentials = "1.5.0", or if you must keep the
beta, add a short comment next to the entry explaining why the beta is required
and what feature or fix depends on it.

Copy link
Copy Markdown
Contributor

@88guri 88guri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

구글 로그인👍 Good~

@nagaeng nagaeng self-requested a review January 5, 2026 07:10
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
feature/mypage/src/main/java/com/teamsolply/solply/mypage/profile/ProfileEditScreen.kt (1)

129-131: 고정 높이와 weight 혼용으로 인한 레이아웃 불일치

일부 Spacer만 고정 높이(height)로 변경되었고, Line 197의 Spacer(modifier = Modifier.weight(12f))는 그대로 유지되어 있습니다. 이로 인해:

  1. 고정 높이 Spacer들은 화면 크기에 관계없이 항상 동일한 공간을 차지
  2. weight Spacer는 남은 공간을 모두 차지
  3. Arrangement.SpaceBetween과 조합 시 의도치 않은 레이아웃 발생 가능

화면 크기별 대응이 필요하다면 weight 방식으로 통일하거나, 고정 레이아웃이 의도라면 모든 Spacer를 고정 높이로 변경하는 것을 권장합니다.

♻️ 일관된 방식으로 수정 제안 (고정 높이 방식)
-        Spacer(modifier = Modifier.weight(12f))
+        Spacer(modifier = Modifier.weight(1f))

또는 모든 spacer를 weight 기반으로 복원:

-            modifier = Modifier.height(16.dp)
+            modifier = Modifier.weight(1f)
-        Spacer(modifier = Modifier.height(32.dp))
+        Spacer(modifier = Modifier.weight(2f))
-        Spacer(modifier = Modifier.height(24.dp))
+        Spacer(modifier = Modifier.weight(1.5f))

Also applies to: 141-141, 169-169

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3a96c3 and d18d30d.

📒 Files selected for processing (2)
  • feature/mypage/src/main/java/com/teamsolply/solply/mypage/profile/ProfileEditScreen.kt
  • feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthViewModel.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthViewModel.kt
🔇 Additional comments (1)
feature/mypage/src/main/java/com/teamsolply/solply/mypage/profile/ProfileEditScreen.kt (1)

117-124: Arrangement.SpaceBetween과 Spacer 조합 재검토 필요

현재 Column이 verticalArrangement = Arrangement.SpaceBetween을 사용하고 있어 자식 요소들 사이에 자동으로 균등한 간격이 배분됩니다. 이 상태에서 고정 높이 Spacer를 추가하면 Spacer 자체가 "콘텐츠"로 간주되어 의도한 레이아웃과 다르게 동작할 수 있습니다.

SpaceBetween을 유지하면서 특정 간격을 조절하려면 Spacer 대신 해당 컴포넌트의 padding이나 Modifier.padding()을 사용하는 것이 더 명확합니다.

@ImHyungsuk ImHyungsuk merged commit afd8991 into develop Jan 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

형석 🐧🍀 그날 인류는 떠올렸다 . 진격의 형석서서서석

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 구글로그인 가보자잇

2 participants